package org.melanesia.beans;

import java.util.List;
import java.util.Map;

import org.melanesia.beans.exceptions.PropertyBeanInstantiationException;


class CompositeSetter implements Setter {

    private List<PropertyAccessor> propertyAccessorList;

    CompositeSetter(List<PropertyAccessor> propertyAccessorList) {
        this.propertyAccessorList = propertyAccessorList;
    }
    
    @Override
    public void set(Object bean, Object value, Map<String, Class<?>> intermediateBeanClasses) {
        
        String propertyPath = null;
        
        for (int i = 0, size = propertyAccessorList.size(); i < size; i++) {
            
            PropertyAccessor accessor = propertyAccessorList.get(i);
            
            if (i+1 == size) {
                
                // Last property in chain
                accessor.set(bean, value, intermediateBeanClasses);
                
            } else {
                
                // Intermediate property
                propertyPath = propertyPath == null ? accessor.getPropertyName() : propertyPath + "." + accessor.getPropertyName();
                
                Object subBean = accessor.get(bean);
                if (subBean == null) {
                    
                    Class<?> subBeanClass = null;
                    if (intermediateBeanClasses != null && intermediateBeanClasses.containsKey(propertyPath)) {
                        subBeanClass = intermediateBeanClasses.get(propertyPath);
                    } else {
                        subBeanClass = accessor.getPropertyClass();
                    }
                    
                    subBean = createBeanInstance(subBeanClass);
                    
                    accessor.set(bean, subBean, intermediateBeanClasses);
                }
                
                bean = subBean;
            }
        }
    }

    private Object createBeanInstance(Class<?> beanClass) {
        try {
        	return beanClass.newInstance();
        } catch (Throwable t) {
        	throw new PropertyBeanInstantiationException("Could not instantiate class \"" + beanClass + "\".", t);
        }
    }

    @Override
    public Class<?> getAcceptedType() {
        return propertyAccessorList.get(propertyAccessorList.size() - 1).getPropertyClass();
    }
    
}
